package com.ssy.lingxi.order.serviceimpl.platform;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.basic.FundModeEnum;
import com.ssy.lingxi.common.constant.basic.PlatformRuleTypeEnum;
import com.ssy.lingxi.common.constant.order.OrderPayTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.entity.BaseOrderPayChannelDO;
import com.ssy.lingxi.order.entity.PlatformPaymentDO;
import com.ssy.lingxi.order.entity.PlatformPaymentMemberDO;
import com.ssy.lingxi.order.model.constant.OrderServiceContants;
import com.ssy.lingxi.order.model.dto.OrderMemberQueryDTO;
import com.ssy.lingxi.order.model.vo.basic.request.OrderMemberIdAndRoleIdVO;
import com.ssy.lingxi.order.model.vo.platform.request.*;
import com.ssy.lingxi.order.model.vo.platform.response.*;
import com.ssy.lingxi.order.repository.BaseOrderPayChannelRepository;
import com.ssy.lingxi.order.repository.BaseOrderRuleRepository;
import com.ssy.lingxi.order.repository.PlatformPaymentRepository;
import com.ssy.lingxi.order.service.base.IBaseCacheService;
import com.ssy.lingxi.order.service.base.IBasePlatformPaymentMemberService;
import com.ssy.lingxi.order.service.base.IBasePlatformPaymentTypeService;
import com.ssy.lingxi.order.service.platform.IPlatformPaymentService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 平台后台 - 会员支付策略相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-08-11
 */
@Service
public class PlatformPaymentServiceImpl implements IPlatformPaymentService {
    @Resource
    private IBaseCacheService baseCacheService;

    @Resource
    private BaseOrderRuleRepository baseOrderRuleRepository;

    @Resource
    private BaseOrderPayChannelRepository baseOrderPayChannelRepository;

    @Resource
    private PlatformPaymentRepository platformPaymentRepository;

    @Resource
    private IBasePlatformPaymentTypeService basePlatformPaymentTypeService;

    @Resource
    private IBasePlatformPaymentMemberService basePlatformPaymentMemberService;

    /**
     * 分页查询支付策略列表
     *
     * @param headers HttpHeaders信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<PlatformPaymentQueryVO>> pagePayments(HttpHeaders headers, PlatformPaymentPageVO pageVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        Pageable pageable = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("createTime").descending());
        Specification<PlatformPaymentDO> specification = (Specification<PlatformPaymentDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();

            if(StringUtils.hasLength(pageVO.getName())) {
                list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + pageVO.getName().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Page<PlatformPaymentDO> pageList = platformPaymentRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(payment -> {
            PlatformPaymentQueryVO queryVO = new PlatformPaymentQueryVO();
            queryVO.setPaymentId(payment.getId());
            queryVO.setName(payment.getName());
            queryVO.setCreateTime(payment.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            queryVO.setStatus(payment.getStatus());
            queryVO.setStatusName(EnableDisableStatus.getNameByCode(payment.getStatus()));
            return queryVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 新增页面，查询支付方式与支付渠道列表
     *
     * @param headers HttpHeaders信息
     * @return 查询结果
     */
    @Override
    public Wrapper<List<PlatformPaymentPayTypeQueryVO>> getPaymentItems(HttpHeaders headers) {
        baseCacheService.needLoginFromManagePlatform(headers);
        //Step 1: 先查找平台基础规则配置中的资金归集模式，如果没有则不允许配置
        List<PlatformPaymentFundModeVO> fundModes = baseOrderRuleRepository.findByRuleTypeAndStatus(PlatformRuleTypeEnum.FUND.getCode(), EnableDisableStatus.ENABLE.getCode()).stream().map(ruleType -> new PlatformPaymentFundModeVO(ruleType.getMethodCode(), ruleType.getMethodName())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(fundModes)) {
            return Wrapper.success();
        }

        //是否包含“平台代收模式”
        boolean containsPlatformFundMode = fundModes.stream().anyMatch(fundMode -> fundMode.getFundMode().equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()));
        //是否包含“会员直接到账模式”
        boolean containsDirectFundMode = fundModes.stream().anyMatch(fundMode -> fundMode.getFundMode().equals(FundModeEnum.DIRECT_TO_ACCOUNT.getCode()));

        //Step 2: 查找支付方式，如没有则不允许配置
        List<BaseOrderPayChannelDO> payChannels = baseOrderPayChannelRepository.findByStatus(EnableDisableStatus.ENABLE.getCode());
        if(CollectionUtils.isEmpty(payChannels)) {
            return Wrapper.success();
        }

        //Step 3: 线上、线下支付、通联支付、跨境电商进口支付，只要存在资金归集模式则返回；
        //        授信额度、货到付款方式必须存在“会员直接到账”模式
        //        建行支付必须存在“平台代收”模式
        return Wrapper.success(payChannels.stream().filter(payChannel -> {
            if(payChannel.getPayType().equals(OrderPayTypeEnum.ONLINE_PAYMENT.getCode()) || payChannel.getPayType().equals(OrderPayTypeEnum.OFFLINE_PAYMENT.getCode()) || payChannel.getPayType().equals(OrderPayTypeEnum.ALLIN_PAY.getCode()) || payChannel.getPayType().equals(OrderPayTypeEnum.COMMERCE_IMPORT_PAY.getCode())) {
                return true;
            } else if(payChannel.getPayType().equals(OrderPayTypeEnum.CCB_PAY.getCode())) {
                return containsPlatformFundMode;
            } else {
                return containsDirectFundMode;
            }
        }).collect(Collectors.groupingBy(BaseOrderPayChannelDO::getPayType)).entrySet().stream().sorted(Map.Entry.comparingByKey()).map(entry -> {
            PlatformPaymentPayTypeQueryVO queryVO = new PlatformPaymentPayTypeQueryVO();
            queryVO.setPayType(entry.getKey());
            queryVO.setPayTypeName(OrderPayTypeEnum.getNameByCode(entry.getKey()));
            if(queryVO.getPayType().equals(OrderPayTypeEnum.ONLINE_PAYMENT.getCode()) || queryVO.getPayType().equals(OrderPayTypeEnum.OFFLINE_PAYMENT.getCode()) || queryVO.getPayType().equals(OrderPayTypeEnum.ALLIN_PAY.getCode()) || queryVO.getPayType().equals(OrderPayTypeEnum.COMMERCE_IMPORT_PAY.getCode())) {
                queryVO.setFundModes(fundModes);
            } else if(queryVO.getPayType().equals(OrderPayTypeEnum.CCB_PAY.getCode())) {
                queryVO.setFundModes(fundModes.stream().filter(fundMode -> fundMode.getFundMode().equals(FundModeEnum.PLATFORM_EXCHANGE.getCode())).collect(Collectors.toList()));
            } else {
                queryVO.setFundModes(fundModes.stream().filter(fundMode -> fundMode.getFundMode().equals(FundModeEnum.DIRECT_TO_ACCOUNT.getCode())).collect(Collectors.toList()));
            }

            queryVO.setChannels(entry.getValue().stream().map(payChannel -> {
                PlatformPaymentPayChannelVO channelVO = new PlatformPaymentPayChannelVO();
                channelVO.setPayChannel(payChannel.getPayChannel());
                channelVO.setPayChannelName(payChannel.getPayChannelName());
                return channelVO;
            }).collect(Collectors.toList()));
            return queryVO;
        }).collect(Collectors.toList()));
    }

    /**
     * 新增会员支付策略
     *
     * @param headers   HttpHeaders信息
     * @param paymentVO 接口参数
     * @return 新增结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> createPayment(HttpHeaders headers, PlatformPaymentVO paymentVO) {
        baseCacheService.needLoginFromManagePlatform(headers);

        //Step 1: 参数校验
        if(!paymentVO.getAllMembers() && CollectionUtils.isEmpty(paymentVO.getMembers())) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_MEMBERS_CAN_NOT_BE_EMPTY);
        }

        //Step 2: 判断是否已经存在
        Pageable pageable = PageRequest.of(0, 1);
        Page<PlatformPaymentDO> pageList;
        if(paymentVO.getAllMembers()) {
            pageList = platformPaymentRepository.findAll(pageable);
        } else {
            Specification<PlatformPaymentDO> specification = (Specification<PlatformPaymentDO>) (root, query, criteriaBuilder) -> {
                List<Predicate> list = new ArrayList<>();
                list.add(criteriaBuilder.isTrue(root.get("allMembers").as(Boolean.class)));

                Join<PlatformPaymentDO, PlatformPaymentMemberDO> memberJoin = root.join("members", JoinType.LEFT);
                for (OrderMemberIdAndRoleIdVO member : paymentVO.getMembers()) {
                    list.add(criteriaBuilder.and(criteriaBuilder.equal(memberJoin.get("memberId").as(Long.class), member.getMemberId()), criteriaBuilder.equal(memberJoin.get("roleId").as(Long.class), member.getRoleId())));
                }

                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.or(list.toArray(p));
            };
            pageList = platformPaymentRepository.findAll(specification, pageable);
        }

        if(pageList.getTotalElements() > 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_EXIST);
        }

        //Step 3: 新增
        PlatformPaymentDO platformPayment = new PlatformPaymentDO();
        platformPayment.setName(paymentVO.getName().trim());
        platformPayment.setCreateTime(LocalDateTime.now());
        platformPayment.setStatus(EnableDisableStatus.ENABLE.getCode());
        platformPayment.setAllMembers(paymentVO.getAllMembers());
        platformPaymentRepository.saveAndFlush(platformPayment);

        //Step 4-1：校验、保存支付方式
        Wrapper<Void> checkResult = basePlatformPaymentTypeService.checkPayTypes(platformPayment, paymentVO.getPayTypes(), true);
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
        }

        //Step 4-2：校验、保存关联会员
        checkResult = basePlatformPaymentMemberService.checkMembers(platformPayment, paymentVO.getMembers(), true);
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
        }

        //Step 5: 再次保存（必须）
        platformPaymentRepository.saveAndFlush(platformPayment);
        return Wrapper.success();
    }

    /**
     * 查询会员支付策略详情
     *
     * @param headers HttpHeaders信息
     * @param idVO    接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PlatformPaymentDetailVO> getPayment(HttpHeaders headers, PlatformPaymentIdVO idVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPaymentDO platformPayment = platformPaymentRepository.findById(idVO.getPaymentId()).orElse(null);
        if(platformPayment == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_DOES_NOT_EXIST);
        }

        PlatformPaymentDetailVO detailVO = new PlatformPaymentDetailVO();
        detailVO.setPaymentId(platformPayment.getId());
        detailVO.setName(platformPayment.getName());
        detailVO.setPayTypes(basePlatformPaymentTypeService.findPayTypes(platformPayment));
        detailVO.setAllMembers(platformPayment.getAllMembers());
        return Wrapper.success(detailVO);
    }

    /**
     * 修改会员支付策略
     *
     * @param headers  HttpHeaders信息
     * @param updateVO 接口参数
     * @return 修改结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> updatePayment(HttpHeaders headers, PlatformPaymentUpdateVO updateVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPaymentDO platformPayment = platformPaymentRepository.findById(updateVO.getPaymentId()).orElse(null);
        if(platformPayment == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_DOES_NOT_EXIST);
        }

        //Step 1: 参数校验
        if(!updateVO.getAllMembers() && CollectionUtils.isEmpty(updateVO.getMembers())) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_MEMBERS_CAN_NOT_BE_EMPTY);
        }

        //Step 2: 判断是否已经存在
        Pageable pageable = PageRequest.of(0, 1);
        Specification<PlatformPaymentDO> specification;
        if(updateVO.getAllMembers()) {
            specification = (Specification<PlatformPaymentDO>) (root, query, criteriaBuilder) -> {
                List<Predicate> list = new ArrayList<>();
                list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), updateVO.getPaymentId()));
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            };

        } else {
            specification = (Specification<PlatformPaymentDO>) (root, query, criteriaBuilder) -> {
                List<Predicate> list = new ArrayList<>();
                list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), updateVO.getPaymentId()));

                List<Predicate> orList = new ArrayList<>();
                orList.add(criteriaBuilder.isTrue(root.get("allMembers").as(Boolean.class)));
                Join<PlatformPaymentDO, PlatformPaymentMemberDO> memberJoin = root.join("members", JoinType.LEFT);
                for (OrderMemberIdAndRoleIdVO member : updateVO.getMembers()) {
                    orList.add(criteriaBuilder.and(criteriaBuilder.equal(memberJoin.get("memberId").as(Long.class), member.getMemberId()), criteriaBuilder.equal(memberJoin.get("roleId").as(Long.class), member.getRoleId())));
                }
                Predicate[] orPredicates = new Predicate[orList.size()];

                list.add(criteriaBuilder.or(orList.toArray(orPredicates)));

                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            };
        }

        Page<PlatformPaymentDO> pageList = platformPaymentRepository.findAll(specification, pageable);
        if(pageList.getTotalElements() > 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_EXIST);
        }

        //Step 3: 更新
        platformPayment.setName(updateVO.getName().trim());
        platformPayment.setCreateTime(LocalDateTime.now());
        platformPayment.setAllMembers(updateVO.getAllMembers());

        //Step 3-1：校验、更新支付方式
        Wrapper<Void> checkResult = basePlatformPaymentTypeService.checkPayTypes(platformPayment, updateVO.getPayTypes(), false);
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
        }

        //Step 3-1：校验、更新关联会员
        checkResult = basePlatformPaymentMemberService.checkMembers(platformPayment, updateVO.getMembers(), false);
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
        }

        //Step 4: 再次保存（必须）
        platformPaymentRepository.saveAndFlush(platformPayment);
        return Wrapper.success();
    }

    /**
     * 分页查询支付策略适用会员列表
     *
     * @param headers HttpHeaders信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<OrderMemberQueryDTO>> pagePaymentMembers(HttpHeaders headers, PlatformPaymentMemberPageVO pageVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPaymentDO platformPayment = platformPaymentRepository.findById(pageVO.getPaymentId()).orElse(null);
        if(platformPayment == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_DOES_NOT_EXIST);
        }

        return basePlatformPaymentMemberService.pageMembers(platformPayment, pageVO.getName(), pageVO.getCurrent(), pageVO.getPageSize());
    }

    /**
     * 修改会员支付策略状态
     *
     * @param headers  HttpHeaders信息
     * @param statusVO 接口参数
     * @return 修改结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> updatePaymentStatus(HttpHeaders headers, PlatformPaymentUpdateStatusVO statusVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPaymentDO platformPayment = platformPaymentRepository.findById(statusVO.getPaymentId()).orElse(null);
        if(platformPayment == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_DOES_NOT_EXIST);
        }

        platformPayment.setCreateTime(LocalDateTime.now());
        platformPayment.setStatus(statusVO.getStatus());
        platformPaymentRepository.saveAndFlush(platformPayment);
        return Wrapper.success();
    }

    /**
     * 删除会员支付策略
     *
     * @param headers HttpHeaders信息
     * @param idVO    接口参数
     * @return 删除结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> deletePayment(HttpHeaders headers, PlatformPaymentIdVO idVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPaymentDO platformPayment = platformPaymentRepository.findById(idVO.getPaymentId()).orElse(null);
        if(platformPayment == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_DOES_NOT_EXIST);
        }

        platformPaymentRepository.delete(platformPayment);
        return Wrapper.success();
    }
}
